﻿using System;
using System.Collections.Generic;
using System.Html;
using System.Linq;
using jQueryApi;

namespace OcenyOpisowe.Client.Controls
{
	/// <summary>
	/// Kontrolka menu.
	/// Pozwala ona na wyświetlanie menu aplikacji wraz z kontrolkami poszczególnych akcji menu.
	/// </summary>
	public class MenuControl : DataBoundControl
	{
		#region Prywatne zmienne klasy
		/// <summary>
		/// Kolekcja elementów menu dodanych do tej kontrolki.
		/// </summary>
		private List<MenuItemControl> _menuItems;
		/// <summary>
		/// Selektor służący do pobierania elementów menu.
		/// </summary>
		private string _menuItemsSelector;
		/// <summary>
		/// Selektor służący do pobierania podelementów menu.
		/// </summary>
		private string _menuSubitemsSelector;
		/// <summary>
		/// Identyfikator szablonu wyglądu menu.
		/// Wykorzystywany do tworzenia kontrolki menu.
		/// </summary>
		private string _menuTemplateIdentifier;
		#endregion

		#region Publiczne właściwości klasy
		/// <summary>
		/// Kolekcja elementów menu, dodanych jako podelementy.
		/// </summary>
		public IEnumerable<MenuItemControl> MenuItems
		{
			get { return _menuItems; }
		}
		#endregion

		#region Konstruktor klasy
		/// <summary>
		/// Inicjuje kontrolkę menu.
		/// </summary>
		public MenuControl()
		{
			_menuItems = new List<MenuItemControl>();
		}
		#endregion

		#region Metoda AddMenuItem
		/// <summary>
		/// Dodaje nowy element menu do tego elementu..
		/// </summary>
		/// <param name="item">Element menu do dodania.</param>
		public void AddMenuItem(MenuItemControl item)
		{
			_menuItems.Add(item);
		}
		#endregion

		#region Metoda ClearMenuItems
		/// <summary>
		/// Metoda czyszcząca kolekcję wszystkich elementów menu.
		/// </summary>
		public void ClearMenuItems()
		{
			_menuItems.Clear();
		}
		#endregion

		#region Metoda RemoveMenuItem
		/// <summary>
		/// Usuwa element z kolekcji elementów menu.
		/// </summary>
		/// <param name="item">Element do usunięcia.</param>
		public void RemoveMenuItem(MenuItemControl item)
		{
			_menuItems.Remove(item);
		}
		#endregion

		#region Metoda LoadMenu
		/// <summary>
		/// Metoda wczytująca zawartość menu z obecnie załadowanej strony.
		/// Po wczytaniu menu usuwa elementy DOM, z których wczytywane były dane tak aby zbędnie nie obciążały
		/// przeglądarki www.
		/// </summary>
		/// <param name="menuDataJson">Ciąg znaków Json zawierający dane wejściowe dla menu.</param>
		private void LoadMenu(object menuDataJson)
		{
			ClearMenuItems();

			Element nextElement = null;

			if(DomElement != null)
			{
				if (ParentDomElement != null)
					ParentDomElement.RemoveChild(DomElement);
				else
				{
					ParentDomElement = DomElement.ParentNode;
					nextElement = DomElement.NextSibling;
					DomElement.ParentNode.RemoveChild(DomElement);
				}
			}

			jQueryObject parsedMenuTemplate =
				(jQueryObject)Script.Literal("$(\"#\" + {0}).tmpl({1})", _menuTemplateIdentifier, menuDataJson);

			if (parsedMenuTemplate == null || parsedMenuTemplate.Length == 0)
			{
				Application.Instance.Console.ReportError("Error ocured during menu initialization!");
				return;
			}
			DomElement = parsedMenuTemplate[0];

			LoadMenuItems(parsedMenuTemplate);

			if (nextElement != null)
				nextElement.InsertBefore(DomElement);
			else
				ParentDomElement.AppendChild(DomElement);
		}
		#endregion

		#region Metoda LoadMenuItems
		/// <summary>
		/// Metoda wczytująca elementy menu z podanego w argumencie obiektu menu.
		/// Obiekt ten został zainicjowany przez metodę LoadMenu.
		/// </summary>
		/// <param name="menuObject">Obiekt menu, z którego wczytać elementy meny.</param>
		private void LoadMenuItems(jQueryObject menuObject)
		{
			jQueryObject menuItemsCollection = jQuery.Select(_menuItemsSelector, menuObject);

			foreach (Element menuItemElement in menuItemsCollection.GetElements())
			{
				MenuItemControl menuItem = new MenuItemControl(this);
				menuItem.DomElement = menuItemElement;
				AddMenuItem(menuItem);
				LoadMenuItemSubitems(menuItem, menuItemElement);
			}
		}
		#endregion

		#region Metoda LoadMenuItemSubitems
		/// <summary>
		/// Metoda wczytująca podelementy dla elementu menu.
		/// </summary>
		/// <param name="menuItem">Element menu, dla którego pobrać podelementy menu.</param>
		/// <param name="menuItemElement">Węzeł, w którym znajdują się informacje o podelementach menu.</param>
		private void LoadMenuItemSubitems(MenuItemControl menuItem, Element menuItemElement)
		{
			jQueryObject menuItemsCollection = jQuery.Select(_menuSubitemsSelector, menuItemElement);

			foreach (Element menuSubitemElement in menuItemsCollection.GetElements())
			{
				MenuItemControl menuSubitem = new MenuItemControl(this);

				menuSubitem.DomElement = menuSubitemElement;

				menuItem.AddMenuItem(menuSubitem);
			}
		}
		#endregion

		#region Metoda OnDataBinding
		/// <summary>
		/// Metoda zawierająca implementację bindowania danych do danej kontrolki.
		/// </summary>
		/// <remarks>
		/// Implementacja bindowania danych jest różna dla różnych kontrolek... więc cóż - metoda abstrakcyjna.
		/// </remarks>
		protected override void OnDataBinding()
		{
			DataSource.BeginDataLoading(OnDataLoaded);
		}
		#endregion

		#region Metoda OnDataLoaded
		/// <summary>
		/// Wywoływane w momencie pobrania danych do menu aplikacji.
		/// </summary>
		/// <param name="data">Dane menu pobrane z serwera.</param>
		/// <param name="status">Status pobierania danych.</param>
		/// <param name="httpRequest">Objekt rządania Ajax.</param>
		private void OnDataLoaded(object data, string status, jQueryXmlHttpRequest httpRequest)
		{
			LoadMenu(data);
		}
		#endregion

		#region Metoda SetMenuItemsSelector
		/// <summary>
		/// Metoda ustawiająca selektor służący do pobrania wszystkich elementów
		/// głównych menu.
		/// </summary>
		/// <param name="menuItemsSelector">Selektor jQuery dla elementów menu.</param>
		public void SetMenuItemsSelector(string menuItemsSelector)
		{
			_menuItemsSelector = menuItemsSelector;
		}
		#endregion

		#region Metoda SetMenuSubitemsSelector
		/// <summary>
		/// Metoda ustawiająca selektor służący do pobierania podelementów menu dla zadanego elementu menu.
		/// </summary>
		/// <param name="menuSubitemsSelector">Selektor jQuery dla podelementow menu.</param>
		public void SetMenuSubitemsSelector(string menuSubitemsSelector)
		{
			_menuSubitemsSelector = menuSubitemsSelector;
		}
		#endregion

		#region Metoda SetMenuTemplate
		/// <summary>
		/// Metoda ustawiająca identyfikator szablonu wygladu menu.
		/// </summary>
		/// <param name="templateIdentifier">Identyfikator szablonu menu.</param>
		public void SetMenuTemplate(string templateIdentifier)
		{
			_menuTemplateIdentifier = templateIdentifier;
		}
		#endregion
	}
}
